package cn.Liujialin.user.service.impl;

import cn.Liujialin.basic.constant.BaseConstant;
import cn.Liujialin.basic.util.AjaxResult;
import cn.Liujialin.basic.util.HttpClientUtils;
import cn.Liujialin.basic.util.MD5Utils;
import cn.Liujialin.basic.util.StrUtils;
import cn.Liujialin.cation.BusinessException;
import cn.Liujialin.user.domain.LoginInfo;
import cn.Liujialin.user.domain.User;
import cn.Liujialin.user.domain.WxUser;
import cn.Liujialin.user.dto.LoginDto;
import cn.Liujialin.user.mapper.LoginInfoMapper;
import cn.Liujialin.user.mapper.UserMapper;
import cn.Liujialin.user.mapper.WxUserMapper;
import cn.Liujialin.user.service.ILoginDtoService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginDtoServiceImpl   implements ILoginDtoService {
    @Autowired
    private LoginInfoMapper loginInfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private UserMapper userMapper;


    @Override
    public Map<String, Object> accountLogin(LoginDto loginDto) {
      // 1、先校验三个数值是否为空 就是用户名 密码 和分别前后端人员
      //注意StringUtils.isEmpty（里面是STR) 因为TYPE不是STR所以
        if (StringUtils.isEmpty(loginDto.getUsername())||StringUtils.isEmpty(loginDto.getPassword())||
                loginDto.getType()==null){
            throw new BusinessException("信息不能为空");
        }
        //2、对比用户名数值是否正确，用户名可以是   对比的后端保存数据来源于登录表
       LoginInfo loginInfo = loginInfoMapper.findUserNmae(loginDto);
        //先判断用户是否存在
        if (loginInfo == null){
            throw new BusinessException("没有此用户");
        }
        //3、如果用户存在还要判断是否被禁用
        if (loginInfo.getDisable()==0){
            throw new BusinessException("此用户已被禁用");
        }
        //4、在判断密码是否正确，密码被加密加盐
        //先根据登录表获取相同的盐值，加上密码对应加密后的数据是否正确
        String salt = loginInfo.getSalt();
        //注意密码在前，盐值在后的顺序
        String byMd5 = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
        if (!loginInfo.getPassword().equals(byMd5)){
            throw new BusinessException("用户或者密码错误");
        }
        //5、全部都正确就要把数据储存
        //先储存到redis中 以key ：token(唯一字串) value：
        // UUID.randomUUID().toString();获取全世界唯一字符串
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,
                loginInfo,//登录成功的用户储存下来
                30,
                TimeUnit.MINUTES//三十分钟过期
        );
        //然后再返回token和logininfo的基本信息给前端 不要把敏感信息返回给前端
        Map<String,Object> map =  new HashMap<>();
        map.put("token",token);
        //考虑细一点，我们不应该把敏感信息返回给前端 密码 salt
        loginInfo.setSalt(null);
        loginInfo.setPassword(null);
        map.put("loginInfo",loginInfo);
        return map;

    }

    @Override
    public AjaxResult wechat(Map<String, String> params) {
        //获取前端的code 校验是不是我们的code
        String code = params.get("code");
        if(StringUtils.isEmpty(code)){
            throw new BusinessException("code不是原来的");
        }
        //发送请求，从微信拿令牌,准备获取信息
        String tokenUrl = BaseConstant.WX_TOKEN_URL
                .replace("APPID",BaseConstant.APPID)
                .replace("SECRET",BaseConstant.SECRET)
                .replace("CODE",code);
        //获取到微信的令牌信息，导入工具类，获取返回的json对象
        String tokenResult = HttpClientUtils.httpGet(tokenUrl);
        if(StringUtils.isEmpty(tokenResult)){
            throw new BusinessException("拿不到微信的令牌，获取不到返回对象");
        }
        //在pom.xml中导入处理json格式的包
        JSONObject jsonObject = JSONObject.parseObject(tokenResult);
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        //拿到openId 去查询t_wxuser表
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        if(wxUser != null && wxUser.getUser_id() != null){
            //用户不是第一次登录 已经扫描过微信登录验证码，直接免密登录就行
            //不要忘记xml，根据用户id查询到用户
            LoginInfo info = loginInfoMapper.findByUserId(wxUser.getUser_id());
            //如果密码一样，则存储在redis
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(
                    token,
                    info,
                    30,
                    TimeUnit.MINUTES
            );
            //返回token和logininfo中基本信息给前端
            Map<String,Object> map =  new HashMap<>();
            map.put("token",token);
            //我们不能把敏感信息发送给前端
            info.setSalt(null);
            info.setPassword(null);
            map.put("loginInfo",info);
            return AjaxResult.me().setResultObj(map);
        }
        //不走免密登录，那就走绑定流程
        //查询不到信息，走绑定流程，需要携带 accessToken 和 openId给前端，方便后续获取微信用户信息
        String binderParams = "?accessToken="+accessToken+"&openId="+openId;
        return AjaxResult.fail(binderParams);

    }


    //走的绑定流程 不走免密登录流程
    @Override
    public Map<String,Object> binderwechat(Map<String, String> params) {
        //校验参数.从前端获取到四个参数电话，验证码以及TOREN和OPenid
        String phone = params.get("phone");
        String verifyCode = params.get("verifyCode");
        String accessToken = params.get("accessToken");
        String openId = params.get("openId");
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId)){
            throw new BusinessException("请输入完整信息");
        }
        //校验验证码是否失效，如果失效重新获取验证码，这里可以参考用户注册时期的代码
        Object o = redisTemplate.opsForValue().get(BaseConstant.BUSINESS_TYPE_BINDER + phone);
        if(o == null){
            throw new BusinessException("验证码已失效，请重新获取验证码");
        }
        //验证码是否一致  不要区分大小写
        //忽略大小写   IgnoreCase   一定不要忘记toString
        String code = o.toString().split(":")[0];
        if(!verifyCode.equalsIgnoreCase(code)){
            throw new BusinessException("验证码输入错误");
        }
        //手机号不能被注册（要查数据库），看平台是否已经注册过phone
        User user = userMapper.findByPhone(phone);
        LoginInfo loginInfo = null;
        if(user != null){
            // 如果已有该用户，直接（先）绑定微信信息，在直接绑定
            loginInfo = loginInfoMapper.findByUserId(user.getId());
        }else{
            //如果没有，那么需要生成t_user t_logininfo  再绑定微信信息
            //6.保存数据（先保存到LoginInfo 然后再保存到user 因为user有外键而LoginInfo没有外键）
            ////        userDto2User 某个方法将userDto转为User对象 用User来接收
            user = phone2User(phone);
            loginInfo = user2LoginInfo(user);
            loginInfoMapper.save(loginInfo);//一定要返回自增ID
            //6.保存user
            user.setLogininfo_id(loginInfo.getId());
            userMapper.save(user);
        }
        //通过微信查询到信息然绑定到平台上
        String wxUserUrl = BaseConstant.WX_USER_URL
                .replace("ACCESS_TOKEN",accessToken)
                .replace("OPENID",openId);
        String wxUserStr = HttpClientUtils.httpGet(wxUserUrl);
        //封装WxUser对象，绑定平台用户
        WxUser wxUser = initWxUser(wxUserStr, user);
        wxUserMapper.save(wxUser);
        //免密登录
        //密码一致：存储redis
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,
                loginInfo,
                30,
                TimeUnit.MINUTES
        );
        //返回token和logininfo基本信息给前端
        //我们不能把敏感信息发送给前端 特别是密码登
        Map<String,Object> map =  new HashMap<>();
        map.put("token",token);
        loginInfo.setSalt(null);
        loginInfo.setPassword(null);
        map.put("loginInfo",loginInfo);
        return map;
    }


    //这里太繁杂，能写就写不能写就拷贝
    private WxUser initWxUser(String wxUserTmp, User user) {
        //装换微信用户信息
        JSONObject jsonObject = JSONObject.parseObject(wxUserTmp);
        WxUser wxUser =  new WxUser();
        wxUser.setUser_id(user.getId());//绑定用户
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }

    //这里从前端主站用户登录里面去拷贝 一模一样的代码
    private LoginInfo user2LoginInfo(User user) {
        LoginInfo loginInfo = new LoginInfo();
        //按照同名原则拷贝属性值
        BeanUtils.copyProperties(user,loginInfo);
        return loginInfo;

    }

    private User phone2User(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        //users.setPassword(userDto.getPassword());将密码加密之后在传入
        //获取32位盐值
        String salt = StrUtils.getComplexRandomString(32);
        //使用盐值加密密码
        String md5Pwd = MD5Utils.encrypByMd5("1" + salt);
        //在将密码传入

        user.setSalt(salt);
        user.setPassword(md5Pwd);
        return user;
    }



}
